#include "VirtualFile.h"
#include <string>
#include <physfs.h>

using namespace boost;
using namespace iostreams;

namespace PhysFS {

device::device(const fileInfo& info)
:file(0)
{
	std::string mode=info.mode;
	if(mode.find('r')!=std::string::npos)
	{
		file=PHYSFS_openRead(info.name);
	}
	else if(mode.find('w')!=std::string::npos)
	{
		file=PHYSFS_openWrite(info.name);
	}
	else if(mode.find('a')!=std::string::npos)
	{
		file=PHYSFS_openAppend(info.name);
	}

	if(!file)
	{
		std::string error("Cannot open file ");
		error+=info.name;
		error+='\n';
		error+=PHYSFS_getLastError();
		throw std::ios_base::failure(error);
	}
	//printf("Open %d\n",file);
}

device::~device()
{
}

std::streamsize device::read(char* s, std::streamsize n)
{
	return PHYSFS_read((PHYSFS_File*)file,s,sizeof(char_type),n);
}

std::streamsize device::write(const char* s, std::streamsize n)
{
	return PHYSFS_write((PHYSFS_File*)file,s,sizeof(char_type),n);
}

stream_offset device::seek(stream_offset off, std::ios_base::seekdir way)
{
	stream_offset seek;
	switch(way)
	{
	case std::ios_base::beg:
		seek=off;
	break;
	case std::ios_base::cur:
		seek=tell()+off;
	break;
	case std::ios_base::end:
		seek=size()-off-1;
	break;
	default:
		throw std::ios_base::failure("Bad seek direction");
	break;
	}

	if(!PHYSFS_seek((PHYSFS_File*)file,seek))
	{
		throw std::ios_base::failure(PHYSFS_getLastError());
	}
	return seek;
}

boost::iostreams::stream_offset device::tell()
{
	return PHYSFS_tell((PHYSFS_File*)file);
}

std::streamsize device::size()
{
	//printf("Size %d\n",file);
	std::streamsize n=PHYSFS_fileLength((PHYSFS_File*)file);
	return n;
}

bool device::eof()
{
	return PHYSFS_eof((PHYSFS_File*)file)!=0;
}

bool device::flush()
{
	return (PHYSFS_flush((PHYSFS_File*)file)!=0);
}

void device::close()
{
	//printf("Close %d\n",file);
	PHYSFS_close((PHYSFS_File*)file);
}

}//namespace

namespace boost { namespace iostreams {
              
template<>     
void close<PhysFS::device>(PhysFS::device& t)
{
	t.close();//close the device
}

} } // End namespace boost::io